任务是一组逻辑工作单元,而线程则是使任务异步执行的机制
Executor提供了一种标准的方法将任务的提交过程和执行过程解耦开来,并用Runnable表示任务,Executor基于生产者-消费者模式,提交任务的操作相当于生产者(生产待完成的工作单元),执行任务的线程则相当于消费者(执行完这些工作单元)。
如果要在程序中实现一个生产者-消费者的设计,那么最简单的方式就是使用Executor
每当看到下面形式的代码时:
new Thread(runnable).start()
,并且你希望获得一种更灵活的执行策略时,请考虑使用Executor来代替Thread。java.lang.concurrent提供了线程池作为实现executor框架的一部分:
1234567891011121314151617181920public class TaskExecutionWebServer {private static final int nTHREADS = 100;private static final Executor exec = Executors.newFixedThreadPool(NTHREADS);public static void main(String[] args) throws IOException {ServerSocket socket = new ServerSocket(80);while (true) {final Socket connection = socket.accept();Runnable task = new Runnable() {public void run() {handleRequest(connection);}};exec.execute(task);}}private static void handleRequest(Socket connection) {}}Executor的实现通常会创建线程来执行任务,但JVM只有在所有(非守护)线程全部终止后才会退出,因此,如果无法正确的关闭Executor,那么JVM将无法结束。
Executor框架使用Runnable作为其基本的任务表示形式,Runnable是一种有很大局限的抽象,虽然run能写入到日志文件或者将结果放入某个共享的数据结构,但它不能返回一个值或抛出一个受检查的异常。
Callable认为主入口点(即call)将返回一个值,并可能抛出一个异常。
Future表示一个任务的生命周期,并提供了相应的方法来判断是否已经完成或取消,以及获取任务的结果和取消任务等。get方法的行为取决于任务的状态(尚未开始、正在运行、已完成)。如果任务已经完成,那么get会立即返回或者抛出一个Exception,如果任务没有完成,那么get将阻塞并直到任务完成。如果任务抛出了异常,那么get将该异常封装为ExecutionException并重新抛出。如果任务被取消,那么get将抛出CancellationException,如果get抛出了ExecutionException,那么可以通过getCause()获得被封装的初始异常。
1234567891011public interface Callable<V> {V call() throws Exception;}public interface Future<V> {boolean cancel(boolean mayInterruptIfRunning);boolean isCancelled();boolean inDone();V get() throws InterruptedException, ExecutionException, CancellationException;v get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, CancellationException, TimeoutException;}要使用Callable来表示无返回值的任务,可使用
Callable<void>